package cn.edu.zju.gis.disasterBE.sever.entity.global;

import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * @author FU Chenhua, SUN Katus
 * @version 1.1, 2021-05-18
 */
public interface JsonAble extends Serializable {
    ObjectMapper MAPPER = new ObjectMapper()
            // FAIL_ON_UNKNOWN_PROPERTIES 在序列化的时候, 如果遇到不认识的字段的处理方式
            // 默认启用特性, 这意味着在遇到未知属性时抛出JsonMappingException. 在引入该特性之前, 这是默认的默认设置. 
            .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
            // FAIL_ON_EMPTY_BEANS 决定了在没有找到类型的存取器时发生了什么（并且没有注释表明它是被序列化的）. 如果启用（默认）, 
            // 将抛出一个异常来指明这些是非序列化类型; 如果禁用了, 它们将被序列化为空对象, 即没有任何属性. 
            // 请注意, 这个特性只对那些没有任何识别注释的“空”bean产生影响（如@json序列化）: 那些有注释的bean不会导致抛出异常.
            .configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
            // 过滤类的属性id
            .setFilterProvider(new SimpleFilterProvider().setFailOnUnknownId(false))
            // 在序列化时, 只有那些值为null或被认为为空的值的属性才不会被包含在内. 
            .setSerializationInclusion(Include.NON_NULL);

    default String toJsonString() throws JsonProcessingException {
        return MAPPER.writeValueAsString(this);
    }

    default byte[] toJsonBytes() throws JsonProcessingException {
        return MAPPER.writeValueAsBytes(this);
    }

    default HashMap<String, Object> toHashMap() throws IOException {
        return MAPPER.readValue(toJsonBytes(), new TypeReference<HashMap<String, Object>>() {
        });
    }

    /**
     * 对象转json字符串
     *
     * @param obj Java对象
     * @return json字符串
     * @throws JsonProcessingException json解析异常
     */
    static String toJsonString(Object obj) throws JsonProcessingException {
        if (obj == null) {
            return null;
        }
        return obj instanceof String ? (String) obj : MAPPER.writeValueAsString(obj);
    }

    /**
     * json字符串转指定对象
     *
     * @param json  json字符串
     * @param clazz 类
     * @param <T>   类泛型
     * @return 指定对象
     * @throws JsonProcessingException json解析异常
     */
    static <T> T jsonToObject(String json, Class<T> clazz) throws JsonProcessingException {
        if (!StringUtils.hasLength(json) || clazz == null) {
            return null;
        }
        return clazz.equals(String.class) ? (T) json : MAPPER.readValue(json, clazz);
    }

    /**
     * json字符串转指定对象List
     *
     * @param json  json字符串
     * @param clazz 成员类
     * @param <T>   成员类泛型
     * @return 指定List
     * @throws JsonProcessingException json解析异常
     */
    static <T> List<T> jsonToList(String json, Class<T> clazz) throws JsonProcessingException {
        if (!StringUtils.hasLength(json) || clazz == null) {
            return null;
        }
        JavaType jt = MAPPER.getTypeFactory().constructParametricType(ArrayList.class, clazz);
        return MAPPER.readValue(json, jt);
    }
}
